Skip to main content

Overview & Context: Why Standardized Agent Communication Matters

The Problem: You’ve built a brilliant customer support agent using Google ADK. Your partner company built an inventory management agent with AWS Bedrock. Your ops team built a monitoring agent with LangGraph. Now they need to work together. In traditional software, we’d just make API calls. But agents aren’t simple REST endpoints—they have long-running tasks, require authentication, need to discover each other’s capabilities, and exchange multimodal data (text, files, structured data). Every team ends up building custom integration code, and nothing talks to anything else without months of engineering work. The Solution: Agent-to-Agent (A2A) Protocol provides a standardized way for agents from different frameworks and organizations to communicate. Think of it as HTTPS for agent collaboration—a universal language that makes heterogeneous agents interoperable.
💡 Key Insight: A2A doesn’t replace orchestration frameworks like CrewAI or LangGraph. Instead, it’s the communication layer that lets agents built with different frameworks collaborate. Use orchestration frameworks for rapid development within your team, expose capabilities via A2A for cross-team and cross-organization integration.
Real-World Adoption:
  • 150+ organizations including Google, AWS, Microsoft, Salesforce, SAP, ServiceNow
  • Transferred to Linux Foundation (June 2025) for vendor-neutral governance
  • Production deployments: Tyson Foods/Gordon Food Service (supply chain), Twilio (communications), Salesforce Agentforce customers
But here’s the reality check: A2A is at version 0.3 (November 2025). It’s technically sound but operationally young. You’re learning a protocol that’s actively shaping the future of multi-agent systems, but production patterns are still emerging.

A2A Fundamentals: How Agents Discover and Communicate (30 min)

The Core Components

A2A defines four essential building blocks that enable agent interoperability: 1. Agent Cards: Business Cards for Agents Every A2A agent publishes metadata at a well-known URL following RFC 8615:
https://your-agent-domain.com/.well-known/agent-card.json
The Agent Card declares:
  • Capabilities: What skills does this agent offer?
  • Authentication: How do I prove I’m authorized?
  • Communication preferences: Do you support streaming? What formats?
  • Contact information: Who maintains this agent?
Example Agent Card for a flight search agent:
{
  "name": "Flight Search Agent",
  "version": "1.0",
  "description": "Searches and books flights across major airlines",
  "capabilities": {
    "skills": [
      {
        "id": "search_flights",
        "description": "Find available flights for given route and dates",
        "input_schema": {
          "type": "object",
          "properties": {
            "origin": {"type": "string"},
            "destination": {"type": "string"},
            "departure_date": {"type": "string", "format": "date"}
          }
        }
      }
    ]
  },
  "authentication": {
    "type": "oauth2",
    "authorization_url": "https://auth.example.com/oauth/authorize"
  },
  "communication": {
    "protocols": ["jsonrpc", "grpc"],
    "supports_streaming": true
  }
}
Think of Agent Cards as the openapi.yaml specification for agents—they enable runtime discovery rather than compile-time integration. 2. Tasks: Long-Running Conversations Unlike REST’s stateless request-response, A2A tasks maintain state across multiple turns:
# Task lifecycle states
SUBMITTED = "submitted"      # Task received, queued
WORKING = "working"          # Agent processing
INPUT_REQUIRED = "input-required"  # Needs human/agent input
COMPLETED = "completed"      # Success
FAILED = "failed"           # Error occurred
CANCELED = "canceled"       # Explicitly stopped
Tasks persist for minutes, hours, or days—appropriate for complex operations like “analyze this quarter’s sales data” or “coordinate with five teams to plan deployment.” 3. Messages: Multimodal Communication Messages contain structured parts supporting text, files, and data:
# Example multimodal message
{
  "role": "user",
  "parts": [
    {
      "type": "text",
      "text": "Analyze these customer support transcripts"
    },
    {
      "type": "file",
      "uri": "https://storage.example.com/transcripts.csv",
      "mime_type": "text/csv"
    },
    {
      "type": "data",
      "data": {
        "analysis_type": "sentiment",
        "time_range": "last_30_days"
      }
    }
  ]
}
This native multimodal support eliminates the need for separate file upload APIs or custom binary protocols. 4. Transport Mechanisms A2A supports three transport options (agents can implement multiple):
TransportUse CasePerformanceComplexity
JSON-RPC 2.0 over HTTPSDefault, web-compatibleGoodLow
gRPC + Protocol BuffersHigh-throughput scenariosExcellentMedium
REST-style HTTPResource-oriented teamsGoodLow
🚀 Production Tip: Start with JSON-RPC over HTTPS. It’s human-readable for debugging, works through corporate firewalls, and handles 99% of use cases. Only move to gRPC if you measure actual performance bottlenecks (thousands of messages/second).

How Agent Discovery Works

Three patterns for finding agents: 1. Well-Known URI (Distributed)
# If you know the agent's domain, fetch its card directly
agent_card_url = "https://inventory-agent.company.com/.well-known/agent-card.json"
card = requests.get(agent_card_url).json()
2. Curated Registries (Centralized)
# Search a registry for agents with specific skills
registry_client.search(skills=["inventory_check", "order_placement"])
# Returns list of agents with their card URLs
3. Private Configuration (Controlled)
# For known internal integrations
KNOWN_AGENTS = {
    "inventory": "https://inventory.internal.com/.well-known/agent-card.json",
    "shipping": "https://shipping.internal.com/.well-known/agent-card.json"
}
⚠️ Common Pitfall: Don’t build a monolithic central registry if you’re just coordinating 3-5 internal agents. Use simple configuration files. Registries add complexity you probably don’t need yet.

Security and Trust in Multi-Agent Systems (20 min)

A2A takes an uncompromising security stance because agents often access sensitive data and make consequential decisions.

Transport Security

HTTPS is mandatory in production. No exceptions. TLS 1.2+ minimum, TLS 1.3+ recommended. This eliminates man-in-the-middle attacks and ensures all agent communication is encrypted. If you’re testing locally, you can use HTTP, but production deployments must use HTTPS with valid certificates.

Authentication Patterns

A2A supports standard web authentication mechanisms:
# OAuth 2.0 with Bearer tokens (recommended)
headers = {
    "Authorization": f"Bearer {access_token}",
    "Content-Type": "application/json"
}

# API Keys (simpler, less secure)
headers = {
    "X-API-Key": api_key,
    "Content-Type": "application/json"
}

# Mutual TLS (highest security)
# Both client and server present certificates
Critical principle: Credentials are transmitted in HTTP headers, never in A2A message payloads. This separates authentication from communication and enables secure logging of message content.

Authorization at the Skill Level

Authentication proves who you are. Authorization determines what you can do.
# An agent authenticates successfully...
authenticated_agent_id = "financial-analysis-agent"

# ...but may lack authorization for certain skills
can_read_data = check_permission(authenticated_agent_id, "read_financial_data")  # True
can_execute_trades = check_permission(authenticated_agent_id, "execute_trades")  # False
This granular control prevents a compromised agent from accessing capabilities beyond its intended scope.

The Trust Chain Problem

When Agent A calls Agent B which calls Agent C, managing credentials becomes complex:
User → Agent A → Agent B → Agent C
Each hop needs:
  • Valid authentication
  • Appropriate authorization
  • Audit logging
  • Timeout handling
🚀 Production Tip: Use short-lived tokens (30 seconds to 5 minutes) for sensitive operations. Yes, this adds complexity with token refresh logic, but it dramatically reduces the blast radius if credentials leak. For financial transactions or PII access, combine with strong customer authentication (SMS codes, biometrics).

What A2A Doesn’t Solve (Yet)

A2A provides the plumbing for secure communication, but higher-level trust problems remain open:
  • Economic models: How do agents negotiate pricing? Who pays when A calls B calls C?
  • Liability allocation: If a multi-agent system makes an error causing loss, who’s responsible?
  • Compliance: How do you satisfy explainability requirements when agents preserve internal opacity?
These are active research areas. For enterprise deployments, you’ll need custom contracts and compliance frameworks beyond the protocol specification.

Implementation with Google ADK (30 min)

Let’s build a practical A2A integration. We’ll create a flight search agent and a hotel booking agent that coordinate to plan travel.

Exposing an Agent via A2A

Google ADK makes this ridiculously simple. Here’s a complete flight search agent exposed via A2A:
from google import adk
from google.adk.a2a import to_a2a
import os

# Define your agent (same as any ADK agent)
flight_agent = adk.Agent(
    name="Flight Search Agent",
    model="gemini-2.0-flash-001",
    instructions="""
    You are a flight search specialist. When users provide origin, 
    destination, and dates, search for available flights and present 
    the top 3 options by price.
    """,
    tools=[
        # MCP tool that calls flight booking API
        adk.tools.mcp_tool(
            server="flight-api",
            tool_name="search_flights"
        )
    ]
)

# Expose via A2A - that's it, one line!
a2a_app = to_a2a(flight_agent, port=8001)

# Run the server
if __name__ == "__main__":
    a2a_app.run()
The to_a2a() function automatically:
  • Generates an Agent Card from your agent definition
  • Starts an HTTP server
  • Serves the card at /.well-known/agent-card.json
  • Handles all A2A protocol message translation
  • Provides authentication endpoints if configured
That’s genuinely all the code required. No manual JSON-RPC handling, no custom routing, no protocol implementation.

Consuming a Remote A2A Agent

Now let’s build a coordinator agent that uses the flight agent remotely:
from google.adk.a2a import RemoteA2aAgent

# Define the remote flight agent
flight_agent = RemoteA2aAgent(
    name="flight_search",
    description="Searches for available flights given origin, destination, and dates",
    agent_card_url="https://flight-agent.example.com/.well-known/agent-card.json",
    # Optional: authentication
    auth={
        "type": "bearer",
        "token": os.getenv("FLIGHT_AGENT_TOKEN")
    }
)

# Define the remote hotel agent
hotel_agent = RemoteA2aAgent(
    name="hotel_search",
    description="Searches for hotels in a given city and date range",
    agent_card_url="https://hotel-agent.example.com/.well-known/agent-card.json"
)

# Create coordinator that uses both
travel_coordinator = adk.Agent(
    name="Travel Coordinator",
    model="gemini-2.0-flash-001",
    instructions="""
    You coordinate travel planning. When users provide destination and dates,
    use the flight_search and hotel_search agents to find options, then
    present a complete travel package.
    """,
    agents=[flight_agent, hotel_agent]  # Remote agents used like local tools!
)

# User makes a request
response = travel_coordinator.run(
    "I need to travel to Tokyo from San Francisco, departing March 15, 
     returning March 22. Find me flight and hotel options."
)
Notice what you didn’t write:
  • HTTP request/response handling
  • JSON-RPC message formatting
  • Error handling and retries
  • Authentication header management
  • Task lifecycle management
ADK’s RemoteA2aAgent acts as a transparent proxy. To Gemini (the LLM), it looks like a local tool. To you (the developer), it looks like a local agent. Under the hood, it’s making A2A protocol calls across the network.

Multi-Framework Integration

Here’s where A2A gets powerful. Let’s use agents from different frameworks:
# Google ADK agent
flight_agent = RemoteA2aAgent(
    name="flight_search",
    agent_card_url="https://flight-agent.example.com/.well-known/agent-card.json"
)

# AWS Bedrock agent (exposed via A2A)
hotel_agent = RemoteA2aAgent(
    name="hotel_search", 
    agent_card_url="https://hotel-bedrock.aws.com/.well-known/agent-card.json"
)

# LangGraph agent (exposed via A2A)
activity_agent = RemoteA2aAgent(
    name="activity_recommendations",
    agent_card_url="https://activity-langgraph.company.com/.well-known/agent-card.json"
)

# Coordinator in ADK orchestrates all three
travel_coordinator = adk.Agent(
    name="Travel Coordinator",
    model="gemini-2.0-flash-001",
    agents=[flight_agent, hotel_agent, activity_agent]
)
Three different frameworks, three different cloud providers, one coordinated workflow. This is what A2A enables.
Quick Check: Before moving on, ensure you can:
  • Explain what an Agent Card contains and why it matters
  • Describe the difference between authentication and authorization in A2A
  • Use to_a2a() to expose an ADK agent via A2A
  • Use RemoteA2aAgent to consume an A2A-enabled agent from any framework

Production Considerations and Current Limitations (15 min)

What Works Well Today

Cross-organization collaboration: The Tyson Foods + Gordon Food Service supply chain integration demonstrates A2A’s strength. Two separate companies, different technology stacks, standardized agent communication for sharing product data and leads. Previously, this would require months of custom API development and contract negotiation. Multi-cloud architectures: AWS demonstrated Google ADK agents running on Amazon Bedrock AgentCore Runtime, coordinating with Strands SDK and OpenAI SDK agents through A2A. The protocol genuinely achieves vendor neutrality. Development velocity: When you need to integrate with an external agent, it’s faster to consume their A2A endpoint than to build custom integration code. The protocol handles the boilerplate.

Current Challenges and Gaps

1. Protocol Maturity A2A is at version 0.3 (November 2025). Expect:
  • Continued specification evolution
  • Occasional breaking changes
  • New features added (gRPC support just arrived in v0.3)
  • Limited production war stories and best practices
⚠️ Reality Check: You’re adopting an emerging standard. For mission-critical production systems, plan for the protocol to evolve and budget engineering time for upgrades. For greenfield projects or new initiatives, A2A is a smart bet on the future.
2. Higher-Level Orchestration Patterns A2A provides communication primitives (messages, tasks, discovery) but doesn’t define:
  • How agents should handle cascading failures
  • How to negotiate conflicting objectives
  • How to optimize resource allocation across agent teams
  • How to implement circuit breakers and backpressure
These patterns exist in microservices architectures (we learned them over 15+ years), but haven’t been codified for multi-agent systems yet. You’ll be pioneering these patterns. 3. Debugging and Observability Distributed multi-agent systems are hard to debug:
User Query → Coordinator Agent (Google ADK)

    → Flight Agent (AWS Bedrock)

        → Pricing API Agent (Custom)

    → Hotel Agent (LangGraph)

    ← Error: "booking_unavailable"
Where did it fail? Was it the LangGraph agent’s logic? A timeout calling the pricing API? A transient network error? Logs are distributed across organizations. Traces span multiple systems. Tools are emerging:
  • A2A Inspector (Google) for message-level debugging
  • Distributed tracing IDs in message headers
  • Centralized logging aggregation
But enterprise-grade observability solutions purpose-built for multi-agent systems don’t exist yet. Budget extra debugging time. 4. Economic and Governance Models Missing from the specification:
  • Standardized pricing discovery (what does this agent cost to invoke?)
  • Billing and settlement (how do costs flow through agent chains?)
  • SLA definitions (what response time can I expect?)
  • Liability allocation (who’s responsible for errors?)
For internal company use, you control both sides and can define these bilaterally. For marketplace scenarios (buying third-party agents), these gaps create friction.

Best Practices We’ve Learned

Start Simple:
  • Begin with 2-3 internal agents using A2A before integrating external services
  • Use JSON-RPC over HTTPS unless you measure performance issues
  • Implement comprehensive logging before hitting production
Design for Failure:
  • Set aggressive timeouts (5-10 seconds for agent calls unless you know they’re slow)
  • Implement retries with exponential backoff
  • Use circuit breakers to prevent cascading failures
  • Make operations idempotent (safe to retry)
Security in Depth:
  • Use short-lived tokens (< 5 minutes) for sensitive operations
  • Implement rate limiting on agent endpoints
  • Log all agent interactions with unique request IDs
  • Apply principle of least privilege (grant minimum necessary permissions)
Monitor Everything:
# Log every agent interaction with structured data
logger.info({
    "event": "agent_call",
    "request_id": request_id,
    "calling_agent": "coordinator",
    "target_agent": "flight_search",
    "skill": "search_flights",
    "latency_ms": 450,
    "status": "success"
})
You can’t debug what you can’t see. Structured logging is non-negotiable.

Hands-On Practice: Building a Multi-Agent Travel System (15 min)

Objective: Build a coordinator agent that uses remote A2A agents for flight search and hotel booking.

Exercise Setup

# Clone starter repository
git clone https://github.com/your-course/a2a-travel-lab.git
cd a2a-travel-lab

# Install dependencies
pip install google-adk[a2a]>=1.6.1

# Set environment variables
export GEMINI_API_KEY="your-key"
export FLIGHT_AGENT_URL="https://flight-agent.example.com/.well-known/agent-card.json"
export HOTEL_AGENT_URL="https://hotel-agent.example.com/.well-known/agent-card.json"

Task 1: Expose a Currency Converter via A2A (10 min)

We’ve provided a working currency converter agent. Your job: expose it via A2A.
# starter/currency_agent.py

from google import adk
from google.adk.a2a import to_a2a

# Provided: working currency converter
currency_agent = adk.Agent(
    name="Currency Converter",
    model="gemini-2.0-flash-001",
    instructions="Convert amounts between currencies using current exchange rates",
    tools=[
        adk.tools.mcp_tool(
            server="exchange-rates",
            tool_name="convert_currency"
        )
    ]
)

# TODO: Expose this agent via A2A on port 8002
# Hint: Use to_a2a() function

if __name__ == "__main__":
    # TODO: Run the A2A server
    pass
Success criteria:
  • Agent Card accessible at http://localhost:8002/.well-known/agent-card.json
  • Card includes currency conversion skill
  • Can send test message via A2A Inspector

Task 2: Build the Travel Coordinator (20 min)

Create a coordinator that uses three remote agents:
# starter/coordinator.py

from google import adk
from google.adk.a2a import RemoteA2aAgent
import os

# TODO: Define remote agents
flight_agent = RemoteA2aAgent(
    # Implement this
)

hotel_agent = RemoteA2aAgent(
    # Implement this
)

currency_agent = RemoteA2aAgent(
    # Implement this
)

# TODO: Create coordinator agent that uses all three
travel_coordinator = adk.Agent(
    # Implement this
)

# Test query
response = travel_coordinator.run("""
    I need to travel from New York to London, March 10-17.
    Find flight and hotel options. Also, what's 2000 USD in GBP?
""")

print(response)
Success criteria:
  • Coordinator successfully calls all three agents
  • Response includes flight options, hotel options, and currency conversion
  • Total execution time < 10 seconds
  • Handles case where one agent is unavailable

Task 3: Add Authentication (Optional Challenge)

Modify your currency agent to require API key authentication:
# Challenge: Add authentication to currency_agent

a2a_app = to_a2a(
    currency_agent,
    port=8002,
    auth={
        "type": "api_key",
        "header_name": "X-API-Key",
        "validate": lambda key: key == os.getenv("EXPECTED_API_KEY")
    }
)
Update the coordinator to include authentication headers when calling the currency agent.